﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI.Design;
using System.ComponentModel.Design;
using System.ComponentModel;
using Terralever.Facebook.UI.FbmlControls;

namespace Terralever.Facebook.UI.Design.FbmlControls
{
    public class FbmlControlDesigner : ControlDesigner
    {
        private class FbmlDesignerActionList : DesignerActionList, ICustomTypeDescriptor
        {
            private class ComponentBoundPropertyDescriptor : PropertyDescriptor
            {
                private static Attribute[] FromCollection(AttributeCollection coll)
                {
                    List<Attribute> atts = new List<Attribute>();
                    foreach (Attribute att in coll)
                        atts.Add(att);
                    return atts.ToArray();
                }

                private PropertyDescriptor m_prop;
                private IComponent m_component;
                public ComponentBoundPropertyDescriptor(PropertyDescriptor property, IComponent component)
                    : base(property.Name, FromCollection(property.Attributes))
                {
                    m_prop = property;
                    m_component = component;
                }

                public override bool CanResetValue(object component)
                {
                    return m_prop.CanResetValue(component);
                }

                public override Type ComponentType
                {
                    get { return m_prop.ComponentType; }
                }

                public override object GetValue(object component)
                {
                    return m_prop.GetValue(component);
                }

                public override bool IsReadOnly
                {
                    get { return m_prop.IsReadOnly; }
                }

                public override Type PropertyType
                {
                    get { return m_prop.PropertyType; }
                }

                public override void ResetValue(object component)
                {
                    m_prop.ResetValue(m_component);
                    m_prop.ResetValue(component);
                }

                public override void SetValue(object component, object value)
                {
                    m_prop.SetValue(m_component, value);
                    m_prop.SetValue(component, value);
                }

                public override bool ShouldSerializeValue(object component)
                {
                    return m_prop.ShouldSerializeValue(m_component);
                }
            }

            private DesignerActionUIService m_uiSvc;
            private PropertyDescriptorCollection m_props;

            public FbmlDesignerActionList(IComponent component)
                : base(component)
            {
                m_uiSvc = (DesignerActionUIService)GetService(typeof(DesignerActionUIService));
            }

            public override DesignerActionItemCollection GetSortedActionItems()
            {
                DesignerActionItemCollection collection = new DesignerActionItemCollection();

                // populate known FBML attributes
                List<PropertyDescriptor> fbmlReqd = new List<PropertyDescriptor>(), fbmlOpt = new List<PropertyDescriptor>();

                PropertyDescriptorCollection props = TypeDescriptor.GetProperties(Component.GetType());
                foreach (PropertyDescriptor pd in props)
                {
                    if (typeof(FbmlControl).IsAssignableFrom(pd.ComponentType) &&
                        pd.Attributes.Contains(new BrowsableAttribute(true)))
                    {
                        if (pd.Attributes.Matches(new FbmlRequiredAttribute { IsRequired = true }))
                        {
                            fbmlReqd.Add(new ComponentBoundPropertyDescriptor(pd, Component));
                        }
                        else
                        {
                            fbmlOpt.Add(new ComponentBoundPropertyDescriptor(pd, Component));
                        }
                    }
                }

                List<PropertyDescriptor> finalSet = new List<PropertyDescriptor>(fbmlReqd);
                finalSet.AddRange(fbmlOpt);
                m_props = new PropertyDescriptorCollection(finalSet.ToArray());

                string elementName = null;
                if (!UseXfbmlSemantics)
                    elementName = string.Concat("FBML element <", Control.ElementName, " />");
                else
                    elementName = string.Concat("FBML element <", Control.ElementName, "></", Control.ElementName, ">");

                var hdr = new DesignerActionHeaderItem(elementName);
                collection.Add(hdr);

                if (fbmlOpt.Find(pd => pd.Name.Equals("UseXfbmlSemantics", StringComparison.Ordinal)) != null)
                {
                    var item = new DesignerActionPropertyItem("UseXfbmlSemantics", "Use XFBML Semantics", elementName, "Specifies whether to use XFBML semantics for Facebook Connect websites or for rendering FBML on Application iframe pages.");
                    item.RelatedComponent = Component;
                    collection.Add(item);
                }

                if (fbmlReqd.Count > 0)
                {
                    collection.Add(new DesignerActionHeaderItem("FBML Required Attributes"));
                    foreach (PropertyDescriptor pd in fbmlReqd)
                    {
                        var item = new DesignerActionPropertyItem(pd.Name, pd.Name, "FBML Required Attributes", pd.Description);
                        item.RelatedComponent = Component;
                        collection.Add(item);
                    }
                }

                if (fbmlOpt.Count > 1)
                {
                    collection.Add(new DesignerActionHeaderItem("FBML Optional Attributes"));

                    foreach (PropertyDescriptor pd in fbmlOpt)
                    {
                        if (!string.Equals(pd.Name,"UseXfbmlSemantics", StringComparison.Ordinal))
                        {
                            var item = new DesignerActionPropertyItem(pd.Name, pd.Name, "FBML Optional Attributes", pd.Description);
                            item.RelatedComponent = Component;
                            collection.Add(item);
                        }
                    }
                }

                return collection;
            }

            public bool UseXfbmlSemantics
            {
                get { return Control.UseXfbmlSemantics; }
                set
                {
                    GetPropertyByName("UseXfbmlSemantics").SetValue(Component, value);
                    m_uiSvc.Refresh(Component);
                }
            }

            private PropertyDescriptor GetPropertyByName(string propName)
            {
                PropertyDescriptor prop = TypeDescriptor.GetProperties(Component)[propName];
                return prop;
            }

            private FbmlControl Control
            {
                get
                {
                    return Component as FbmlControl;
                }
            }


            #region ICustomTypeDescriptor Members

            public AttributeCollection GetAttributes()
            {
                return TypeDescriptor.GetAttributes(Component);
            }

            public string GetClassName()
            {
                return TypeDescriptor.GetClassName(Component);
            }

            public string GetComponentName()
            {
                return TypeDescriptor.GetComponentName(Component);
            }

            public TypeConverter GetConverter()
            {
                return TypeDescriptor.GetConverter(Component);
            }

            public EventDescriptor GetDefaultEvent()
            {
                return TypeDescriptor.GetDefaultEvent(Component);
            }

            public PropertyDescriptor GetDefaultProperty()
            {
                return TypeDescriptor.GetDefaultProperty(Component);
            }

            public object GetEditor(Type editorBaseType)
            {
                return TypeDescriptor.GetEditor(Component, editorBaseType);
            }

            public EventDescriptorCollection GetEvents(Attribute[] attributes)
            {
                return TypeDescriptor.GetEvents(Component, attributes);
            }

            public EventDescriptorCollection GetEvents()
            {
                return TypeDescriptor.GetEvents(Component);
            }

            public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
            {
                return m_props;
            }

            public PropertyDescriptorCollection GetProperties()
            {
                return m_props;
            }

            public object GetPropertyOwner(PropertyDescriptor pd)
            {
                return Component;
            }

            #endregion
        }

        public override DesignerActionListCollection ActionLists
        {
            get
            {
                DesignerActionListCollection lists = new DesignerActionListCollection();
                lists.Add(new FbmlDesignerActionList(Component));
                return lists;
            }
        }
    }
}
